﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Microsoft.Crm.Sdk;

namespace TTprotons.Crm.ExternalView.Service.Common
{
    public static class Utils
    {
        /// <summary>
        /// Check if the relevant BusinessEntityCollection contains is null or empty.
        /// </summary>
        /// <param name="collection">The Business Entity Collection object</param>
        /// <returns>True if collection is empty, and vice versa</returns>
        public static bool IsNullOrEmpty(this BusinessEntityCollection collection)
        {
            return collection == null || collection.BusinessEntities == null || collection.BusinessEntities.Count == 0;
        }

        /// <summary>
        /// Shorthand notation for string.IsNullOrEmpty
        /// </summary>
        /// <param name="theString">The string</param>
        /// <returns>True if string is null or empty, and vice versa</returns>
        public static bool IsNullOrEmpty(this string theString)
        {
            return string.IsNullOrEmpty(theString);
        }

        /// <summary>
        /// Check if the relevant List contains is null or empty.
        /// </summary>
        /// <param name="collection">The collection object</param>
        /// <returns>True if collection is empty, and vice versa</returns>
        public static bool IsNullOrEmpty<T>(this List<T> collection)
        {
            return collection == null || collection.Count == 0;
        }

        /// <summary>
        /// Gets the property value.
        /// </summary>
        /// <typeparam name="T">Desired return type</typeparam>
        /// <param name="entity">CRM Dynamic entity</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <returns>Property value</returns>
        public static T GetPropertyValue<T>(this DynamicEntity entity, string propertyName)
        {
            // Retrieve the matching property.
            object theProperty = entity.Properties.FirstOrDefault(i => i.Name.EqualsIgnoreCase(propertyName));

            // If property not found, return the default value.
            if (theProperty == null) return default(T);

            object value = null;
            var strPropertyType = theProperty.GetType().Name;

            switch (strPropertyType)
            {
                case "KeyProperty":
                    value = ((KeyProperty)theProperty).Value.Value;
                    break;

                case "StringProperty":
                    value = ((StringProperty)theProperty).Value;
                    break;

                case "PicklistProperty":
                    if (typeof(T).Equals(typeof(string)))
                        value = ((PicklistProperty)theProperty).Value.name;
                    else if (typeof(T).Equals(typeof(int)))
                        value = ((PicklistProperty)theProperty).Value.Value;

                    break;

                case "CrmBooleanProperty":
                    value = ((CrmBooleanProperty)theProperty).Value.Value;
                    break;

                case "CrmDateTimeProperty":
                    value = ((CrmDateTimeProperty)theProperty).Value.UserTime;
                    break;

                case "CrmDecimalProperty":
                    value = ((CrmDecimalProperty)theProperty).Value.Value;
                    break;

                case "CrmFloatProperty":
                    value = ((CrmFloatProperty)theProperty).Value.Value;
                    break;

                case "CrmMoneyProperty":
                    value = ((CrmMoneyProperty)theProperty).Value.Value;
                    break;

                case "CrmNumberProperty":
                    value = ((CrmNumberProperty)theProperty).Value.Value;
                    break;

                case "LookupProperty":
                    if (typeof(T).Equals(typeof(string)))
                        value = ((LookupProperty)theProperty).Value.name;
                    else if (typeof(T).Equals(typeof(Guid)))
                        value = ((LookupProperty)theProperty).Value.Value;

                    break;

                case "CustomerProperty":
                    if (typeof(T).Equals(typeof(string)))
                        value = ((CustomerProperty)theProperty).Value.name;
                    else if (typeof(T).Equals(typeof(Guid)))
                        value = ((CustomerProperty)theProperty).Value.Value;

                    break;

                case "StatusProperty":
                    if (typeof(T).Equals(typeof(string)))
                        value = ((StatusProperty)theProperty).Value.name;
                    else if (typeof(T).Equals(typeof(Guid)))
                        value = ((StatusProperty)theProperty).Value.Value;

                    break;

                case "StateProperty":
                    value = ((StateProperty)theProperty).Value;
                    break;

                case "EntityNameReferenceProperty":
                    value = ((EntityNameReferenceProperty)theProperty).Value.Value;
                    break;
            }

            try
            {
                if (value != null)
                {
                    return (T)value;
                }
            }
            catch
            { }

            return default(T);
        }

        /// <summary>
        /// Equalses the ignore case.
        /// </summary>
        /// <param name="firstString">The first string.</param>
        /// <param name="secondString">The second string.</param>
        /// <returns></returns>
        public static bool EqualsIgnoreCase(this string firstString, string secondString)
        {
            if (string.IsNullOrEmpty(firstString) && string.IsNullOrEmpty(secondString)) return true;
            if (string.IsNullOrEmpty(firstString) || string.IsNullOrEmpty(secondString)) return false;

            return firstString.Equals(secondString, StringComparison.InvariantCultureIgnoreCase);
        }

        /// <summary>
        /// Apply the encoding notation to the xml.
        /// </summary>
        /// <param name="element"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string Encode(this XElement element, string encoding)
        {
            if (element == null)
                element = XElement.Parse("<viewresult morerecords=\"false\" />");

            var sb = new StringBuilder(element.ToString());
            sb.Insert(0, string.Format("<?xml version=\"1.0\" encoding=\"{0}\"?>", encoding));

            return sb.ToString();
        }

        /// <summary>
        /// Clean the string from the special characters prior to querying the CRM.
        /// </summary>
        /// <param name="theString">String to be cleaned</param>
        /// <returns>Cleaned string</returns>
        public static string CrmCleanString(this string theString)
        {
            return theString.IsNullOrEmpty() ? string.Empty : theString.Replace("%", "");
        }

        public static bool IsGuid(this string theString)
        {
            try
            {
                var theGuid = new Guid(theString);
                return true;
            }
            catch (Exception)
            { return false; }
        }

        public static bool IsInteger(this string theString)
        {
            int theInt;
            return int.TryParse(theString, out theInt);
        }

        public static bool IsPicklist(this XElement element)
        {
            if (element == null) return false;

            return element.Attribute("name") != null && element.Value.IsInteger();
        }

        public static string GetAttributeValue(this XElement element, string attributeName)
        {
            if (element == null) return string.Empty;

            var attr = element.Attribute(attributeName);
            return attr == null ? string.Empty : attr.Value;
        }
    }
}